import {isStarted} from '../start';
import {
  getAppsToLoad,
  getAppsToMount,
  getAppsToUnmount,
  getMountedApps
} from '../application/apps';
import {toLoadPromise} from '../lifecycles/load'
import {toBootstrapPromise} from "../lifecycles/bootstrap";
import {toUnmountPromise} from "../lifecycles/unmount";
import {toMountPromise} from "../lifecycles/mount";
import {callCapturedEvents} from "./hijackLocations";

let appChangesUnderway = false;
let changesQueue = [];

export function invoke(pendings = []/*←第一次是没有值的 故赋个初值*/,eventArgs) {
  console.log('invoke eventArgs:',eventArgs);
  if (appChangesUnderway) { // 第一次肯定不会走这
    console.log('===appChangesUnderway===');
    return new Promise((resolve, reject) => {
      changesQueue.push({
        success: resolve,
        failure: reject,
        eventArgs
      })
    })
  }

  appChangesUnderway = true;

  if (isStarted()/*←mySingleSpa.start()后才会置为true*/) {
    console.log('===performAppChanges===');
    return performAppChanges()
  }

  // 按需预加载 但并不执行
  console.log('===loadApps===');
  return loadApps();

  function loadApps() {
    // 1. 获取需要被load的app
    // 2. 从远端拉取app(通过用户传递的app的loadFunction) 但不会执行app的生命周期
    // 此时app的status在拉取到app config后状态转为 NOT_BOOTSTRAPPED
    return Promise.all(getAppsToLoad().map(toLoadPromise)).then((res) => {
      CallAllLocationEvents()
      console.log('res:',res);
      return finish()
    }).catch(e => {
      CallAllLocationEvents()
      console.error(e)
    });
  }


  /** /home(appA)->/index(appB) */
  // 先卸载 再 加载
  function performAppChanges() {
    /** unmount不需要的app*/
    const unmountPromise = getAppsToUnmount().map(toUnmountPromise);
    const unmountPromises = Promise.all(unmountPromise);

    /** 有可能目标app模块 没有被加载过 故可能会存在需要load的*/
    // will load app
    const loadApps = getAppsToLoad();
    const loadPromises = loadApps.map(app => {
      return toLoadPromise(app)
        .then(toBootstrapPromise)
        //等unmount完之后 再mount
        .then(() => unmountPromises)
        .then(() => toMountPromise(app));
    }); // bootstrap执行后 app.status就为NOT_MOUNTED了

    /** 有可能是之前已经加载过的 当时路由跳转到另外一个页面 现在又切回来了*/
    // will mount app
    const mountApps = getAppsToMount()
      // 去重 因为后面会concat
      .filter(app => loadApps.indexOf(app) === -1);
    const mountPromises = mountApps.map(app => {
      return toBootstrapPromise(app)
        .then(() => unmountPromises)
        .then(() => toMountPromise(app));
    });

    const loadAndMountPromises = loadPromises.concat(mountPromises);

    return Promise.all(loadAndMountPromises).then(()=>{
      CallAllLocationEvents();
      return finish();
    }, e => {
      CallAllLocationEvents();
      pendings.forEach(item => item.failure(e));
      throw e
    });
  }

  function finish() {
    let returnValue = getMountedApps()

    if (pendings.length) {
      pendings.forEach(item => item.success(returnValue));
    }

    appChangesUnderway = false;

    //假设系统正在加载 /home 对应的appA
    //但此时 如果route突然变为了 /index
    //appA加载完成之后(还没有mount), 必须立马加载appB

    if (changesQueue.length) { // 有可能是路由变了 有可能是用户手动调用(registerApplication 或则 start方法)
      const backup = changesQueue; // 上一次invoke调用期间 加入队列等待的内容
      changesQueue = [];
      return invoke(backup);
    }

    return returnValue;
  }

  function CallAllLocationEvents(){
    console.log('CallAllLocationEvents-------------------');
    // eventsQueue.length >0 说明 路由发生了改变
    const eventsQueue = pendings && pendings.length && pendings.filter(item => {
      return !!item.eventArgs; // 说明是路由发生改变
    }).forEach(event => {
      callCapturedEvents(event);
    });

    // 第一次进来 如果也有eventArgs
    eventArgs && callCapturedEvents(eventArgs)
  }
}
